﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CarbonExchange.AmeeQuery;
using CarbonExchange.Dal;

namespace CarbonExchange.Bll
{
    public class AnswerItemFactory : FactoryBase<AnswerItem>
    {
        public AnswerItemFactory() : base() { }

        public AnswerItemFactory(IAmeeCommand ameeCommand) : base(ameeCommand) { }

        public AnswerItemFactory(Context dalContext) : base(dalContext) { }

        public AnswerItemFactory(IAmeeCommand ameeCommand, Context dalContext) : base(ameeCommand, dalContext) { }

        protected override void MarkItemForDeletion(AnswerItem item)
        {
            var tmp = item.Convert(DalContext);
            if (tmp != null)
            {
                DalContext.AnswerItems.DeleteOnSubmit(tmp);
            }
        }

        protected override void Validate(IQueryable<AnswerItem> items, CarbonExchange.Bll.Exceptions.ValidationException exp)
        {
            items.Validate(exp, DalContext);
        }

        protected override void PopulateDataChanges(AnswerItem item, object dataItem)
        {
            var tmp = dataItem as Dal.AnswerItem;
            if (tmp != null)
            {
                item.Id = tmp.Id;
                item.CID = tmp.CID;
                item.QuestionId = tmp.Answer.Question.Id;
                item.QuestionName = tmp.Answer.Question.QuestionName;
            }
        }

        protected override object GetDataItemForUpdate(AnswerItem item)
        {
            return item.Convert(DalContext);
        }

        private IQueryable<JoinHelper> GetSelection()
        {
            return DalContext.AnswerItems.Select(x => new JoinHelper(x, x.Answer.Question, x.Answer.Audit.AuditKey, x.Answer.Question.SectionId));
        }

        internal class JoinHelper   
        {
            internal JoinHelper(Dal.AnswerItem answerItem)
            {
                this.AnswerItem = answerItem;
                this.Question = answerItem.Answer.Question;
                this.AuditKey = answerItem.Answer.Audit.AuditKey;
            }

            internal JoinHelper(Dal.AnswerItem answerItem, Dal.Question question, string auditKey, int sectionId)
            {
                this.AnswerItem = answerItem;
                this.Question = question;
                this.AuditKey = auditKey;
            }

            internal Dal.AnswerItem AnswerItem { get; private set; }
            internal Dal.Question Question { get; private set; }
            internal string AuditKey { get; private set; }
        }

        public IQueryable<AnswerItem> GetAllByUserSectionId(int userSectionId)
        {
            return DalContext.UserSections.Where(x => x.Id == userSectionId).Join(DalContext.AnswerItems.Where(x => !x.Answer.Deleted && !x.Answer.Question.Deleted), x => new { SectionId = x.SectionId, AuditId = x.AuditId }, y => new { SectionId = y.Answer.Question.SectionId, AuditId = y.Answer.AuditId }, (x, y) => new JoinHelper(y)).Convert();
            //return DalContext.AnswerItems.Where(x => x.Answer.Question.Section.UserSections == userSectionId).Select(x => new JoinHelper(x)).Convert();
        }
    }

    internal static class AnswerItemConverter
    {

        internal static IQueryable<AnswerItem> Convert(this IQueryable<AnswerItemFactory.JoinHelper> source)
        {
            return source.Select(x => ConvertItem(x));
        }

        internal static AnswerItem Convert(this AnswerItemFactory.JoinHelper source)
        {
            return ConvertItem(source);
        }

        private static AnswerItem ConvertItem(AnswerItemFactory.JoinHelper item)
        {
            if (item != null)
            {
                return new AnswerItem()
                {
                    AmeeId = item.AnswerItem.AmeeId,
                    AnswerId = item.AnswerItem.AnswerId,
                    Footprint = item.AnswerItem.Footprint,
                    Id = item.AnswerItem.Id,
                    Name = item.AnswerItem.Name,
                    Path = item.AnswerItem.Path,
                    CID = item.AnswerItem.CID,
                    QuestionId = item.Question.Id,
                    QuestionName = item.Question.QuestionName,
                    AuditKey = item.AuditKey
                };
            }
            else
            {
                return null;
            }
        }

        internal static IQueryable<Dal.AnswerItem> Convert(this IQueryable<AnswerItem> source, Dal.Context context)
        {
            return source.Select(x => ConvertItem(x, context));
        }

        internal static Dal.AnswerItem Convert(this AnswerItem source, Dal.Context context)
        {
            return ConvertItem(source, context);
        }

        private static Dal.AnswerItem ConvertItem(AnswerItem item, Dal.Context context)
        {
            if (item != null)
            {
                Dal.AnswerItem tmp = null;
                if (item.Id == 0)
                {
                    tmp = new Dal.AnswerItem();
                    tmp.AnswerId = item.AnswerId;
                }
                else
                {
                    tmp = context.AnswerItems.Where(x => x.Id == item.Id).Single();
                }
                
                item.CheckConcurent(tmp.CID);

                tmp.AmeeId = item.AmeeId;
                tmp.Footprint = item.Footprint;
                tmp.Name = item.Name;
                tmp.Path = item.Path;
                return tmp;
            }
            else
            {
                return null;
            }
        }

        internal static void Validate(this IQueryable<AnswerItem> source, Exceptions.ValidationException e, Dal.Context context)
        {
            if (source != null)
            {
                foreach (var item in source)
                {
                    item.Validate(e, context);
                }
                var duplicates = source.GroupBy(x => new { x.AnswerId, x.Name }).Where(x => x.Count() > 1);
                foreach (var duplicate in duplicates)
                {
                    e.Add(string.Format("Name '{0}' is specified more than once for AnswerId '{1}'", duplicate.Key.Name, duplicate.Key.AnswerId));
                }
            }
        }

        internal static void Validate(this AnswerItem source, Exceptions.ValidationException e, Dal.Context context)
        {
            if (source != null)
            {
                if (source.AnswerId == 0)
                {
                    e.Add("AnswerId must be specified");
                }

                if (string.IsNullOrEmpty(source.Name))
                {
                    e.Add("Name must be specified");
                }
                else if (context.AnswerItems.Where(x => x.AnswerId == source.AnswerId && x.Name == source.Name && x.Id != source.Id).Count() > 0)
                {
                    e.Add(string.Format("Name '{0}' already exists for this Answer", source.Name));
                }
            }
        }
    }

}
